#include "auto_ptr.hpp"
#include "unique_ptr.hpp"
#include "shared_ptr.hpp"
#include "weak_ptr.hpp"
#include <vector>
#include <pthread.h>

void auto_ptr_test()
{
    auto_ptr<std::vector<int>> p1(new std::vector<int>());
    p1->push_back(1);
    std::cout << "p1->size():" << p1->size() << std::endl;
    auto_ptr<std::vector<int>> p2;
    std::cout << "p1.get():" << p1.get() << std::endl;
    std::cout << "p2.get():" << p2.get() << std::endl;
    p2 = p1;
    std::cout << "p1.get():" << p1.get() << std::endl;
    std::cout << "p2.get():" << p2.get() << std::endl;

    auto_ptr<std::vector<int>> p3(p2);
    std::cout << "p1.get():" << p1.get() << std::endl;
    std::cout << "p2.get():" << p2.get() << std::endl;
    std::cout << "p3.get():" << p3.get() << std::endl;

    (*p3).pop_back();
    std::cout << "p3->size():" << p3->size() << std::endl;
}

void unique_ptr_test()
{
    unique_ptr<std::vector<int>> p1(new std::vector<int>());
    p1->push_back(1);
    std::cout << "p1->size():" << p1->size() << std::endl;
    unique_ptr<std::vector<int>> p2;
    std::cout << "p1.get():" << p1.get() << std::endl;
    std::cout << "p2.get():" << p2.get() << std::endl;

    // 禁止
    // p2 = p1;
    //auto_ptr<std::vector<int>> p3(p2);
    
}

void shared_ptr_test()
{
    shared_ptr<std::vector<int>> p1(new std::vector<int>());
    p1->push_back(1);
    std::cout << "p1->UseCnt():" << p1.UseCnt() << std::endl;
    shared_ptr<std::vector<int>> p2;
    std::cout << "p1.UseCnt():" << p1.UseCnt() << std::endl;
    std::cout << "p2.UseCnt():" << p2.UseCnt() << std::endl;
    p2 = p1;
    std::cout << "p1.UseCnt():" << p1.UseCnt() << std::endl;
    std::cout << "p2.UseCnt():" << p2.UseCnt() << std::endl;

    shared_ptr<std::vector<int>> p3;
    p2 = p3;
    std::cout << "p1.UseCnt():" << p1.UseCnt() << std::endl;
    std::cout << "p2.UseCnt():" << p2.UseCnt() << std::endl;
    std::cout << "p3.UseCnt():" << p3.UseCnt() << std::endl;


    shared_ptr<std::vector<int>> p4(p1);
    std::cout << "p1.UseCnt():" << p1.UseCnt() << std::endl;
    std::cout << "p3.UseCnt():" << p4.UseCnt() << std::endl;
}

void* f1(void* args)
{
    shared_ptr<int>* ptr = (shared_ptr<int>*)args;
    for(int i = 0; i < 10000; i++)
    {
        shared_ptr<int> ptr1(*ptr);
        std::cout << ptr->UseCnt() << std::endl;
    }
    return nullptr;
}

template<class T>
struct DelArr
{
	void operator()(const T* ptr)
	{
		std::cout << "delete[]: " << ptr << std::endl;
		delete[] ptr;
	}
};

void shared_ptr_thread_test()
{
    shared_ptr<int, DelArr<int>> ptr(new int[10], DelArr<int>());
    pthread_t tid1, tid2, tid3;
    pthread_create(&tid1, nullptr, f1, (void*)&ptr);
    pthread_create(&tid2, nullptr, f1, (void*)&ptr);
    pthread_create(&tid3, nullptr, f1, (void*)&ptr);
    pthread_join(tid1, nullptr);
    pthread_join(tid2, nullptr);
    pthread_join(tid3, nullptr);
    std::cout << ptr.UseCnt() << std::endl;
}

void shared_ptr_co_test()
{
    struct ListNode
    {
        weak_ptr<ListNode> _next;
        weak_ptr<ListNode> _prev;
        int _val;
        ~ListNode()
        {
            std::cout << "~ListNode()" << std::endl;
        }
    };
    shared_ptr<ListNode> node1(new ListNode);
    shared_ptr<ListNode> node2(new ListNode);

    node1->_next = node2;
    node2->_prev = node1;
}


int main()
{
    // auto_ptr_test();
    // unique_ptr_test();
    // shared_ptr_test();
    // shared_ptr_thread_test();
    shared_ptr_co_test();
}